/**
  ETFDAQ Project -- online from ETFAna Online by SUN Yazhou
  \class TAQueue
  \brief a fifo 
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2023-06-08
  \date 2023-06-08 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                    </tr>
  <tr>  <td>2023-06-08   <td>Asia Sun    <td>file created                   </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#ifndef TAQueue_h
#define TAQueue_h

#include <semaphore.h>
#include <pthread.h>
#include <signal.h>
#include "online_shm.h"
#include "TAReadShm.h" // use its peeksem
#include "item.h"

class TAQueue{
public:
  TAQueue(DaqType daqType = kPXI);
  virtual ~TAQueue();

  /// add an item from src to the queue
  virtual void Add(const void *src);
  /// add an item from file descriptor to the queue
  virtual bool Add(int fd); ///< \retval: true: receive one event from LAN

  ///< pop out an item from the queue to dst
  /// \param idx index of the obtained event
  virtual void Pop(void *dst, unsigned &idx);
  ///< pop out an item from the queue to file descriptor fd
  /// \param size is the length of the transferred item in bytes
  virtual bool Pop(int fd, size_t *size = nullptr);

  int NLoaded(){ return TAReadShm::peeksem(fNLoaded); }
  int NEmpty(){ return TAReadShm::peeksem(fNEmpty); }
  /// \retval 0: empty; 1: full
  double full(){ return NLoaded()/double(kMAX_ITEM_NUM); }
  const item *ItemOut() const{ return &fItem[fWrite]; }
  const item *ItemIn() const{ return &fItem[fRead]; }
  virtual void Reset();

  virtual void Close(); ///< do some clean-ups
  void SetACK(bool a = true){ fACK = a; }
  int NAdded() const{ return fNAdded; }
  void ClearNAdded(){ fNAdded = 0; }

  static int sockState(int fd); ///< get socket status
  static const char *sockStateC(int fd); ///< get socket status - string
  static bool isSockClosed(int fd); ///< to tell if fd has been closed

  static const size_t kMAX_ITEM_NUM = 8192; // 8192*2: enough to store 1 spill

protected:
  item fItem[kMAX_ITEM_NUM];
  DaqType fDaqType;
  int fMAX_ITEM_LEN, fMAX_ITEM_SIZE; // differ in *sizeof(int)

  size_t fRead; ///< index of the next item to read
  size_t fWrite; ///< index of the next item to write
  pthread_mutex_t fMutex;
  sem_t fNEmpty, fNLoaded;

  struct sigaction fsa; ///< pointer to the daq shm

  // variables used in nonblock read and write //
  // for system nonblock read function
  int fNHasRead, fNLastRead, fNLeftToRead;
  bool fReadDone; ///< indicate whether an event has been completely read
  int fEvSizeRead; ///< event length in bytes
  // here is for the system nonblock write function
  int fNHasWritten, fNLastWritten, fNLeftToWrite;
  bool fWriteDone; ///< indicate whether an event has been completely read
  int fEvSizeWrite; ///< event length in bytes

  bool fACK; ///< whether the current event has been completely received
  int fNAdded; ///< nof added items - used for beam info monitoring
};

#endif
